#include "Random.hpp"
#include <mt19937.h>

#ifdef _WIN32
#include <windows.h>

SystemRandom::SystemRandom(){
    CryptAcquireContextW((HCRYPTPROV *)&pd, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
}

SystemRandom::~SystemRandom(){
    CryptReleaseContext((HCRYPTPROV )pd, 0);
}

size_t SystemRandom::operator ()(size_t mod){
    size_t ret;
    CryptGenRandom((HCRYPTPROV )pd,sizeof(ret),(unsigned char*)&ret);
    return ret%mod;
}

size_t SystemRandom::operator ()(){
    size_t ret;
    CryptGenRandom((HCRYPTPROV )pd,sizeof(ret),(unsigned char*)&ret);
    return ret;
}

#else
#include <unistd.h>
#include <fcntl.h>

SystemRandom::SystemRandom()
{
    pd=open("/dev/urandom",O_RDONLY);
}

SystemRandom::~SystemRandom()
{
    close(pd);
}

size_t SystemRandom::operator ()(size_t mod)
{
    size_t ret;
    read(pd,&ret,sizeof(ret));
    return ret%mod;
}

size_t SystemRandom::operator()()
{
    size_t ret;
    read(pd,&ret,sizeof(ret));
    return ret;
}

#endif

Mt19937Random::Mt19937Random(unsigned seed)
{
    engine=create_mt19937(seed);
}

Mt19937Random::~Mt19937Random()
{
    destroy_mt19937((mt19937_engine*)engine);
}

unsigned Mt19937Random::operator()(unsigned mod)
{
    return mt19937_randuint32((mt19937_engine*)engine)%mod;
}

unsigned Mt19937Random::operator ()()
{
    return mt19937_randuint32((mt19937_engine*)engine);
}
